//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#include <buola/image.h>

#include <cmath>
#include <buola/image/ccolor.h>
#include <buola/algorithm/case.h>

namespace buola { namespace img {

std::unordered_map<std::wstring,CColor> CColor::mNamedColors;

void CColor::SetHSV(double h,double s,double v)
{
    if(s==0)
    {
        r=v;
        g=v;
        b=v;
    }
    else
    {
        h=h-floor(h/360)*360;

        int hi=((int)h)/60;
        double f=h/60.0-hi;
        double p=v*(1-s);
        double q=v*(1-f*s);
        double t=v*(1-(1-f)*s);

        if(hi==0)
        {
            r=v;
            g=t;
            b=p;
        }
        else if(hi==1)
        {
            r=q;
            g=v;
            b=p;
        }
        else if(hi==2)
        {
            r=p;
            g=v;
            b=t;
        }
        else if(hi==3)
        {
            r=p;
            g=q;
            b=v;
        }
        else if(hi==4)
        {
            r=t;
            g=p;
            b=v;
        }
        else //if(hi==5) (comment avoids probably uninitialized warning)
        {
            r=v;
            g=p;
            b=q;
        }
    }
}

CColor::CColor(const std::wstring &pString,double pAlpha)
{
    if(iswdigit(pString[0]))
    {
        *this=CColor(to_<int>(pString));
    }
    else
    {
        if(mNamedColors.empty())
            InitStatic();

        auto lColor=mNamedColors.find(tolower_clone(pString));
        if(lColor==mNamedColors.end())
            throw XNotFound("color name not found");

        *this=lColor->second;
    }

    a=pAlpha;
}

void CColor::GetHSV(double &h,double &s,double &v) const
{
    //conical approach
    if(r==g&&g==b)
    {
        s=0;
        v=r;
        h=0; //don't care, really
    }
    else
    {
        if(r>g)
        {
            if(g>=b) //r,g,b
            {
                s=(r-b)/r;
                h=(0+(g-b)/(r-b))*60;
                v=r;
            }
            else if(b>r) //b,r,g
            {
                s=(b-g)/b;
                h=(4+(r-g)/(b-g))*60;
                v=b;
            }
            else //r,b,g
            {
                s=(r-g)/r;
                h=(6+(g-b)/(r-g))*60;
                v=r;
            }
        }
        else
        {
            if(r>b) //g,r,b
            {
                s=(g-b)/g;
                h=(2+(b-r)/(g-b))*60;
                v=g;
            }
            else if(b>g) //b,g,r
            {
                s=(b-r)/b;
                h=(4+(r-g)/(b-r))*60;
                v=b;
            }
            else //g,b,r
            {
                s=(g-r)/g;
                h=(2+(b-r)/(g-r))*60;
                v=g;
            }
        }
    }
}

CColor CColor::GetDarker(int pQ) const
{
    double h,s,v;
    GetHSV(h,s,v);

    CColor lReturn;

    v=v-v*pQ/100;
    lReturn.SetHSVA(h,s,v,a);

    return lReturn;
}

CColor CColor::GetLighter(int pQ) const
{
    double h,s,v;
    GetHSV(h,s,v);

    CColor lReturn;

    v=v+v*pQ/100;
    if(v>1)
    {
        s=s-(v-1);
        if(s<0) s=0;
        v=1;
    }

    lReturn.SetHSVA(h,s,v,a);

    return lReturn;
}

void CColor::InitStatic()
{
    //colors from http://www.learningwebdesign.com/colornames.html
    mNamedColors[L"aliceblue"]=rgb8(240,248,255);
    mNamedColors[L"antiquewhite"]=rgb8(250,235,215);
    mNamedColors[L"aqua"]=rgb8(0,255,255);
    mNamedColors[L"aquamarine"]=rgb8(127,255,212);
    mNamedColors[L"azure"]=rgb8(240,255,255);
    mNamedColors[L"beige"]=rgb8(245,245,220);
    mNamedColors[L"bisque"]=rgb8(255,228,196);
    mNamedColors[L"black"]=rgb8(0,0,0);
    mNamedColors[L"blanchedalmond"]=rgb8(255,255,205);
    mNamedColors[L"blue"]=rgb8(0,0,255);
    mNamedColors[L"blueviolet"]=rgb8(138,43,226);
    mNamedColors[L"brown"]=rgb8(165,42,42);
    mNamedColors[L"burlywood"]=rgb8(222,184,135);
    mNamedColors[L"cadetblue"]=rgb8(95,158,160);
    mNamedColors[L"chartreuse"]=rgb8(127,255,0);
    mNamedColors[L"chocolate"]=rgb8(210,105,30);
    mNamedColors[L"coral"]=rgb8(255,127,80);
    mNamedColors[L"cornflowerblue"]=rgb8(100,149,237);
    mNamedColors[L"cornsilk"]=rgb8(255,248,220);
    mNamedColors[L"crimson"]=rgb8(220,20,60);
    mNamedColors[L"cyan"]=rgb8(0,255,255);
    mNamedColors[L"darkblue"]=rgb8(0,0,139);
    mNamedColors[L"darkcyan"]=rgb8(0,139,139);
    mNamedColors[L"darkgoldenrod"]=rgb8(184,134,11);
    mNamedColors[L"darkgray"]=rgb8(169,169,169);
    mNamedColors[L"darkgreen"]=rgb8(0,100,0);
    mNamedColors[L"darkkhaki"]=rgb8(189,183,107);
    mNamedColors[L"darkmagenta"]=rgb8(139,0,139);
    mNamedColors[L"darkolivegreen"]=rgb8(85,107,47);
    mNamedColors[L"darkorange"]=rgb8(255,140,0);
    mNamedColors[L"darkorchid"]=rgb8(153,50,204);
    mNamedColors[L"darkred"]=rgb8(139,0,0);
    mNamedColors[L"darksalmon"]=rgb8(233,150,122);
    mNamedColors[L"darkseagreen"]=rgb8(143,188,143);
    mNamedColors[L"darkslateblue"]=rgb8(72,61,139);
    mNamedColors[L"darkslategray"]=rgb8(47,79,79);
    mNamedColors[L"darkturquoise"]=rgb8(0,206,209);
    mNamedColors[L"darkviolet"]=rgb8(148,0,211);
    mNamedColors[L"deeppink"]=rgb8(255,20,147);
    mNamedColors[L"deepskyblue"]=rgb8(0,191,255);
    mNamedColors[L"dimgray"]=rgb8(105,105,105);
    mNamedColors[L"dodgerblue"]=rgb8(30,144,255);
    mNamedColors[L"firebrick"]=rgb8(178,34,34);
    mNamedColors[L"floralwhite"]=rgb8(255,250,240);
    mNamedColors[L"forestgreen"]=rgb8(34,139,34);
    mNamedColors[L"fuchsia"]=rgb8(255,0,255);
    mNamedColors[L"gainsboro"]=rgb8(220,220,220);
    mNamedColors[L"ghostwhite"]=rgb8(248,248,255);
    mNamedColors[L"gold"]=rgb8(255,215,0);
    mNamedColors[L"goldenrod"]=rgb8(218,165,32);
    mNamedColors[L"gray"]=rgb8(128,128,128);
    mNamedColors[L"green"]=rgb8(0,128,0);
    mNamedColors[L"greenyellow"]=rgb8(173,255,47);
    mNamedColors[L"honeydew"]=rgb8(240,255,240);
    mNamedColors[L"hotpink"]=rgb8(255,105,180);
    mNamedColors[L"indianred"]=rgb8(205,92,92);
    mNamedColors[L"indigo"]=rgb8(75,0,130);
    mNamedColors[L"ivory"]=rgb8(255,240,240);
    mNamedColors[L"khaki"]=rgb8(240,230,140);
    mNamedColors[L"lavender"]=rgb8(230,230,250);
    mNamedColors[L"lavenderblush"]=rgb8(255,240,245);
    mNamedColors[L"lawngreen"]=rgb8(124,252,0);
    mNamedColors[L"lemonchiffon"]=rgb8(255,250,205);
    mNamedColors[L"lightblue"]=rgb8(173,216,230);
    mNamedColors[L"lightcoral"]=rgb8(240,128,128);
    mNamedColors[L"lightcyan"]=rgb8(224,255,255);
    mNamedColors[L"lightgoldenrodyellow"]=rgb8(250,250,210);
    mNamedColors[L"lightgreen"]=rgb8(144,238,144);
    mNamedColors[L"lightgrey"]=rgb8(211,211,211);
    mNamedColors[L"lightpink"]=rgb8(255,182,193);
    mNamedColors[L"lightsalmon"]=rgb8(255,160,122);
    mNamedColors[L"lightseagreen"]=rgb8(32,178,170);
    mNamedColors[L"lightskyblue"]=rgb8(135,206,250);
    mNamedColors[L"lightslategray"]=rgb8(119,136,153);
    mNamedColors[L"lightsteelblue"]=rgb8(176,196,222);
    mNamedColors[L"lightyellow"]=rgb8(255,255,224);
    mNamedColors[L"lime"]=rgb8(0,255,0);
    mNamedColors[L"limegreen"]=rgb8(50,205,50);
    mNamedColors[L"linen"]=rgb8(250,240,230);
    mNamedColors[L"magenta"]=rgb8(255,0,255);
    mNamedColors[L"maroon"]=rgb8(128,0,0);
    mNamedColors[L"mediumaquamarine"]=rgb8(102,205,170);
    mNamedColors[L"mediumblue"]=rgb8(0,0,205);
    mNamedColors[L"mediumorchid"]=rgb8(186,85,211);
    mNamedColors[L"mediumpurple"]=rgb8(147,112,219);
    mNamedColors[L"mediumseagreen"]=rgb8(60,179,113);
    mNamedColors[L"mediumslateblue"]=rgb8(123,104,238);
    mNamedColors[L"mediumspringgreen"]=rgb8(0,250,154);
    mNamedColors[L"mediumturquoise"]=rgb8(72,209,204);
    mNamedColors[L"mediumvioletred"]=rgb8(199,21,133);
    mNamedColors[L"midnightblue"]=rgb8(25,25,112);
    mNamedColors[L"mintcream"]=rgb8(245,255,250);
    mNamedColors[L"mistyrose"]=rgb8(255,228,225);
    mNamedColors[L"moccasin"]=rgb8(255,228,181);
    mNamedColors[L"navajowhite"]=rgb8(255,222,173);
    mNamedColors[L"navy"]=rgb8(0,0,128);
    mNamedColors[L"oldlace"]=rgb8(253,245,230);
    mNamedColors[L"olive"]=rgb8(128,128,0);
    mNamedColors[L"olivedrab"]=rgb8(107,142,35);
    mNamedColors[L"orange"]=rgb8(255,165,0);
    mNamedColors[L"orangered"]=rgb8(255,69,0);
    mNamedColors[L"orchid"]=rgb8(218,112,214);
    mNamedColors[L"palegoldenrod"]=rgb8(238,232,170);
    mNamedColors[L"palegreen"]=rgb8(152,251,152);
    mNamedColors[L"paleturquoise"]=rgb8(175,238,238);
    mNamedColors[L"palevioletred"]=rgb8(219,112,147);
    mNamedColors[L"papayawhip"]=rgb8(255,239,213);
    mNamedColors[L"peachpuff"]=rgb8(255,218,185);
    mNamedColors[L"peru"]=rgb8(205,133,63);
    mNamedColors[L"pink"]=rgb8(255,192,203);
    mNamedColors[L"plum"]=rgb8(221,160,221);
    mNamedColors[L"powderblue"]=rgb8(176,224,230);
    mNamedColors[L"purple"]=rgb8(128,0,128);
    mNamedColors[L"red"]=rgb8(255,0,0);
    mNamedColors[L"rosybrown"]=rgb8(188,143,143);
    mNamedColors[L"royalblue"]=rgb8(65,105,225);
    mNamedColors[L"saddlebrown"]=rgb8(139,69,19);
    mNamedColors[L"salmon"]=rgb8(250,128,114);
    mNamedColors[L"sandybrown"]=rgb8(244,164,96);
    mNamedColors[L"seagreen"]=rgb8(46,139,87);
    mNamedColors[L"seashell"]=rgb8(255,245,238);
    mNamedColors[L"sienna"]=rgb8(160,82,45);
    mNamedColors[L"silver"]=rgb8(192,192,192);
    mNamedColors[L"skyblue"]=rgb8(135,206,235);
    mNamedColors[L"slateblue"]=rgb8(106,90,205);
    mNamedColors[L"slategray"]=rgb8(112,128,144);
    mNamedColors[L"snow"]=rgb8(255,250,250);
    mNamedColors[L"springgreen"]=rgb8(0,255,127);
    mNamedColors[L"steelblue"]=rgb8(70,130,180);
    mNamedColors[L"tan"]=rgb8(210,180,140);
    mNamedColors[L"teal"]=rgb8(0,128,128);
    mNamedColors[L"thistle"]=rgb8(216,191,216);
    mNamedColors[L"tomato"]=rgb8(253,99,71);
    mNamedColors[L"turquoise"]=rgb8(64,224,208);
    mNamedColors[L"violet"]=rgb8(238,130,238);
    mNamedColors[L"wheat"]=rgb8(245,222,179);
    mNamedColors[L"white"]=rgb8(255,255,255);
    mNamedColors[L"whitesmoke"]=rgb8(245,245,245);
    mNamedColors[L"yellow"]=rgb8(255,255,0);
    mNamedColors[L"yellowgreen"]=rgb8(154,205,50);
}

const std::vector<CColor> &nice_colors()
{
    static std::vector<CColor> lColors;
    if(lColors.empty())
    {
        lColors.push_back(img::CColor(L"darkslateblue"));
        lColors.push_back(img::CColor(L"yellowgreen"));
        lColors.push_back(img::CColor(L"tomato"));
        lColors.push_back(img::CColor(L"gold"));
        lColors.push_back(img::CColor(L"purple"));
        lColors.push_back(img::CColor(L"royalblue"));
        lColors.push_back(img::CColor(L"seagreen"));
        lColors.push_back(img::CColor(L"mediumorchid"));
        lColors.push_back(img::CColor(L"brown"));
        lColors.push_back(img::CColor(L"lightsteelblue"));
        lColors.push_back(img::CColor(L"coral"));
        lColors.push_back(img::CColor(L"steelblue"));
        lColors.push_back(img::CColor(L"darkseagreen"));
        lColors.push_back(img::CColor(L"hotpink"));
        lColors.push_back(img::CColor(L"teal"));
        lColors.push_back(img::CColor(L"darkorange"));
        lColors.push_back(img::CColor(L"orchid"));
        lColors.push_back(img::CColor(L"forestgreen"));
        lColors.push_back(img::CColor(L"firebrick"));
        lColors.push_back(img::CColor(L"indigo"));
        lColors.push_back(img::CColor(L"orange"));
        lColors.push_back(img::CColor(L"darkslategray"));
        lColors.push_back(img::CColor(L"deeppink"));
        lColors.push_back(img::CColor(L"peru"));
        lColors.push_back(img::CColor(L"slategray"));
        lColors.push_back(img::CColor(L"indianred"));
        lColors.push_back(img::CColor(L"slateblue"));
        lColors.push_back(img::CColor(L"darkmagenta"));
        lColors.push_back(img::CColor(L"sienna"));
        lColors.push_back(img::CColor(L"midnightblue"));
        lColors.push_back(img::CColor(L"orangered"));
        lColors.push_back(img::CColor(L"maroon"));
    }
    
    return lColors;
}

const CColor &nice_color(int i)
{
    const auto &lColors=nice_colors();
    return lColors[i%lColors.size()];
}

/*namespace img*/ } /*namespace buola*/ }
